<?php
namespace app\models;
/**
 * @desc instore model
 */
use app\models\BaseModel;
use app\dao\ProductDAO;
use app\dao\InstoreDAO;
use app\dao\InstoreDetailDAO;
use app\dao\TransactionDAO;
use app\enum\EnumOther;
use Yii;
use app\enum\EnumOriginType;
use yii\composer\Installer;
use app\dao\StockPileDAO;
use app\dao\ProductUpdateLogDAO;
use app\helpers\Utility;
use app\dao\WarehouseDAO;

class InstoreModel extends BaseModel
{
	/**
	 * @desc 覆盖父方法返回对象
	 * @author liaojianwen
	 * @date 2016-11-24
	 * @return InstoreModel
	 */
	public static function model($className=__CLASS__)
	{
		return parent::model($className);
	}
	
	/**
	 * @desc 查询商品信息
	 * @param string $name
	 * @param [] $pageInfo
	 * @author liaojianwen
	 * @date 2016-11-18
	 */
	public function getProducts($pageInfo, $name)
	{
		if(empty($pageInfo)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','params is empty');
		}
		$result = ProductDAO::getInstance()->getProducts($pageInfo, $name);
		if(empty ( $result )) {
			return $this->handleApiFormat ( EnumOther::ACK_FAILURE,'','no data found');
		}
		return $this->handleApiFormat(EnumOther::ACK_SUCCESS,$result);
	
	}
	
	/**
	 * @desc 保存入库单
	 * @param [] $head 入库单头
	 * @param [] $detail 入库单明细
	 * @param $id //入库单id //有就是编辑,没有就是新增
	 * @param $remove 删除的明细
	 * @author liaojianwen
	 * @date 2016-11-22
	 */
	public function saveInstore($head, $detail,$remove,$id)
	{
		if(empty($head)){
			return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'head is empty' );
		}
		if (empty ( $detail )) {
			return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'detail is empty' );
		}
		
		//清掉为空的元素
		foreach ($head as $k =>$hed){
			if(empty($hed)){
				unset($head[$k]);
			}
		}
		foreach ($detail as $k=> $det){
			foreach ($det as $j => $deet){
				if(empty($deet)){
					unset($detail[$k][$j]);
				}
			}
		}
		$tr = Yii::$app->db->beginTransaction();
		try{
			// 表头信息
			$head ['instore_date'] = strtotime ( $head ['instore_date'] );
			$cond_head = "instore_id =:id";
			$param_head = [ 
					':id' => $id 
			];
			$Iid = InstoreDAO::getInstance ()->ireplaceinto ( $head, $cond_head, $param_head, true );
			if (! $Iid) {
				$tr->rollBack();
				return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'save instore_head failure' );
			}
			// 表单明细
	// 		InstoreDetailDAO::getInstance()->iupdate(['delete_flag' => EnumOther::DELETED], "instore_id =:did", [':did'=>$Iid]);// 先删除后没有删除的数据更新回来
			//删除的明细
			foreach ($remove as $move){
				$res_remove = InstoreDetailDAO::getInstance()->iupdate(['delete_flag'=>EnumOther::DELETED], "instore_det_id = :det_id", [':det_id'=>$move['instore_det_id']]);
				if(!$res_remove){
					$tr->rollBack();
					$this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'remove instore_det_id:'+$move['instore_det_id'] +'failed');
				}
			}
			foreach ( $detail as &$det ) {
				$det ['instore_id'] = $Iid;
				$det ['delete_flag'] = EnumOther::NO_DELETE;
				$cond_det = "instore_id = :id and instore_det_id = :lid";
				$param_det = [ 
						':id' => $Iid,
						':lid' => isset($det ['instore_det_id'])?$det['instore_det_id']:0,
				];
	
				$res_det = InstoreDetailDAO::getInstance ()->ireplaceinto ( $det, $cond_det, $param_det, true );
				if (! $res_det) {
					$tr->rollBack();
					return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'save instore_detail failure' );
				}
			}
			$tr->commit();
			return $this->handleApiFormat ( EnumOther::ACK_SUCCESS, '' );
		} catch (\Exception $e){
			$tr->rollBack();
			return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', $e->getMessage());
		}
	}
	
// 	/**
// 	 * @desc 保存入库单
// 	 * @param [] $head 入库单头
// 	 * @param [] $detail 入库单明细
// 	 * @param $id //入库单id //有就是编辑,没有就是新增
// 	 * @author liaojianwen
// 	 * @date 2016-11-22
// 	 */
// 	public function saveInstore($head, $detail,$id)
// 	{
// 		if(empty($head)){
// 			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','head is empty');
// 		}
// 		if(empty($detail)){
// 			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','detail is empty');
// 		}
// 		$tr = Yii::$app->db->beginTransaction();
// 		try{
// 			//表头信息
// 			$head['instore_date'] = strtotime($head['instore_date']);
// 			$head['create_time'] = time();
// 			$Iid= InstoreDAO::getInstance()->iinsert($head,true);
// 			if(!$Iid){
// 				$tr->rollBack();
// 				return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'save instore_head failure');
// 			}
	
// 			//表单明细
// 			foreach($detail as &$det){
// 				$det['instore_id'] = $Iid;
// 				$det['create_time'] = time();
// 				$res_det = InstoreDetailDAO::getInstance()->iinsert($det,true);
// 				if(!$res_det){
// 					$tr->rollBack();
// 					return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'save instore_detail failure');
// 				}
	
// 				//出入库明细
// 				$column_trans = array(
// 						'goods_id' => $det['goods_id'],
// 						'quantity' =>  $det['quantity'],
// 						'origin_type' => $head['instore_type'],
// 						'origin_id' => $head['instore_no'],
// 						'origin_line_id' => $res_det,//原单序号
// 						'warehouse_id' => $head['warehouse_id'],
// 						'flag'=>EnumOther::IN_FLAG,
// 				);
	
// 				$res_trans = TransactionDAO::getInstance()->iinsert($column_trans,true);
// 				if(!$res_trans){
// 					$tr->rollBack();
// 					return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'save transaction failure');
// 				}
	
// 				//更新product quantity 这个方法没法完成，写多一个方法
// 				// 				$pro_select = ProductDAO::getInstance()->updateByPk($det['goods_id'], ['quantity'=>$det['quantity']]);
// 				$pro_select = ProductDAO::getInstance()->updateAllCounters(['quantity'=>$det['quantity']],"product_id =:id",[':id'=>$det['goods_id']]);
	
// 				if(!$pro_select){
// 					$tr->rollBack();
// 					return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'update product quantity failure');
// 				}
	
// 			}
				
				
// 			$tr->commit();
// 			return $this->handleApiFormat(EnumOther::ACK_SUCCESS,'');
				
// 		} catch(\Exception $e){
// 			$tr->rollBack();
// 			dd($e->getMessage());
// 			return false;
// 		}
	
// 	}
	
	/**
	 * @desc 获取入库单列表数据
	 * @param [] $pageInfo 
	 * @param [] $condition //查询条件 
	 * @author liaojianwen
	 * @date 2016-11-24
	 */
	public function getInstores($pageInfo, $condition, $filter)
	{
		if(empty($pageInfo)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','param is empty');
		}
		$result = InstoreDAO::getInstance()->getInstores($condition, $filter, $pageInfo);
		if(empty($result)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','no data found');
		}
		return $this->handleApiFormat(EnumOther::ACK_SUCCESS,$result);
	}
	
	/**
	 * @desc 根据id 获取入库单信息
	 * @param int $id //入库单id
	 * @author liaojianwen
	 * @date 2016-11-24
	 */
	public function getInstoreInfo($id)
	{
		if(empty($id)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','param is empty');
		}
		$in_head = InstoreDAO::getInstance()->getInstoreHead($id);
		if(empty($in_head)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','head data found');
		}
		$in_det = InstoreDetailDAO::getInstance()->getInstoreDet($id);
		if(empty($in_det)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','detail data found');
		}
		$result['head'] = $in_head;
		$result['det'] = $in_det;
		return $this->handleApiFormat(EnumOther::ACK_SUCCESS,$result);
	}
	
	/**
	 * @desc 确认入库单
	 * @author liaojianwen
	 * @date 2016-11-25
	 */
	public function confirmInstore($id)
	{
		if (! $id) {
			return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'param is empty' );
		}
		$id = (int)$id;
		$tr = Yii::$app->db->beginTransaction ();
		try {
			$re_confirm = InstoreDAO::getInstance ()->updateByPk ( $id, [ 
					'confirm_flag' => EnumOther::CONFIRM 
			] );
			if (! $re_confirm) {
				$tr->rollBack ();
				return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'confirm fail' );
			}
			$fields = [ 
					'h.instore_no',
					'd.goods_id',
					'd.quantity',
					'h.instore_type',
					'd.instore_det_id',
					'h.warehouse_id',
					'h.instore_date',
					'd.unit',
					'd.base_quantity',
					'd.base_unit',
					'd.base_price',
// 					'h.vendor_id'
			];
			$conditions = "d.instore_id =:id and d.delete_flag = :flag";
			$params = [ 
				':id' => $id,
				':flag' => EnumOther::NO_DELETE 
			];
			$joinArray = [ 
				[ 
					'instore h',
					"h.instore_id = d.instore_id" 
				] 
			];
			$instore_det = InstoreDetailDAO::getInstance ()->iselect ( $fields, $conditions, $params, 'all', 'd.instore_det_id ASC', $joinArray, 'd' );
			if (! $instore_det) {
				$tr->rollBack ();
				return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'select det fail' );
			}
			// 出入库明细
			foreach ( $instore_det as $det ) {
				$PRODUCT = ProductDAO::getInstance()->iselect(["price","quantity"], "product_id = :pid", [':pid'=>$det['goods_id']],'one');
				if(isset($PRODUCT['price'])){
					$price = $PRODUCT['price'];
				} else {
					$price = 0;
				}
				
				$column_trans = array (
						'goods_id' => $det ['goods_id'],
						'quantity' => $det ['base_quantity'],
						'quantity_unit'=> $det['base_unit'],
						'origin_type' => $det ['instore_type'],
						'origin_id' => $det ['instore_no'],
						'origin_line_id' => $det ['instore_det_id'], // 原单序号
						'origin_time'=> $det ['instore_date'],
						'warehouse_id' => $det ['warehouse_id'],
						// 'vendor_id'=> $det['vendor_id'],
						'init_num' => $PRODUCT['quantity'],//上期数量
						'flag' => EnumOther::IN_FLAG
				);
				
				
				$res_trans = TransactionDAO::getInstance ()->iinsert ( $column_trans, true );
				if (! $res_trans) {
					$tr->rollBack ();
					return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'save transaction failure' );
				}
				
				//商品成本价计算 --start
				$priceRes = PurchaseModel::model()->AccountingPrice($det['goods_id'], $det['base_quantity'], $det['base_price'], true, EnumOriginType::origin_other_in);
				if(!$priceRes){
					$tr->rollBack();
					return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'accounting price fail');
				}
				//////////////////-----end
				
				// 更新product quantity 加库存
				$WAREHOUSE = WarehouseDAO::getInstance()->iselect("is_scrapped,warehouse_name", "warehouse_id =:wid", [':wid'=>$det['warehouse_id']],'one');
				if(isset($WAREHOUSE['is_scrapped'])){
					if($WAREHOUSE['is_scrapped'] != '1'){//不是报废单
						$pro_select = ProductDAO::getInstance ()->updateAllCounters ( [
								'quantity' => $det ['base_quantity'] ,
								'amount'=> $price * $det['base_quantity'],
						], "product_id =:id", [
								':id' => $det ['goods_id']
						] );
						
						if (! $pro_select) {
							$tr->rollBack ();
							return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'update product quantity failure' );
						}
					} 
				} else {
					$tr->rollBack();
					return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','select scrapped failed');
				}
				
				//product_update_log 商品更新记录//
				$_order_type = Utility::getArrayValue(EnumOriginType::$origin_type, $det['instore_type']);
				
				$log_columns = [
					'product_id' => $det ['goods_id'],	
					'update_num' => $det ['base_quantity'],
					'num_unit' => $det['base_unit'],
					'origin_id' => $id,
					'origin_no' => $det['instore_no'],
					'origin_line_id'=> $det['instore_det_id'],
					'origin_type'=> $det['instore_type'],
					'update_time'=>strtotime(date('Y-m-d')),
					'flag'=> EnumOther::IN_FLAG,
					'initial_num'=> $PRODUCT['quantity'],//上期数量
					'remark'=> $_order_type .($WAREHOUSE['warehouse_name']?:''). EnumOther::PLUS,
					'warehouse_id' => $det['warehouse_id'],
					'create_man' => Yii::$app->user->id,
				];
				$res_log = ProductUpdateLogDAO::getInstance()->iinsert($log_columns, true);
				if(! $res_log){
					$tr->rollBack();
					return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'product update log failure');
				}
				
				//分仓列表数据的插入或者更新--start
				$stock_conditions = "warehouse_id =:wid and product_id=:pid and delete_flag =:flag";
				$stock_params = [
					':wid'=>$det['warehouse_id'],
					':pid'=>$det['goods_id'],
					':flag'=> EnumOther::NO_DELETE,
				];
				$stock_select = StockPileDAO::getInstance()->iselect("stock_pile_id", $stock_conditions, $stock_params,'one');
				if(! $stock_select){
					//没有数据，插入新数据
					$stock_columns = [
						'warehouse_id'=> $det['warehouse_id'],
						'product_id'=> $det['goods_id'],
						'quantity'=> $det['base_quantity'],	
						'quantity_unit'=> $det['base_unit'],
					];
					$stock_insert = StockPileDAO::getInstance()->iinsert($stock_columns, true);
					if(! $stock_insert){
						$tr->rollBack ();
						return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'insert stock pile failure' );
					}
				} else {
					//有数据，更新数据
					$stock_update = StockPileDAO::getInstance()->updateAllCounters(['quantity'=>$det['base_quantity']], $stock_conditions, $stock_params);
					if(! $stock_update){
						$tr->rollBack();
						return $this->handleApiFormat(EnumOther::ACK_FAILURE, '','update stock pile failure');
					}
				}
				//分仓 --end
 
			}
			$tr->commit();
			return $this->handleApiFormat(EnumOther::ACK_SUCCESS,'');
		} catch ( \Exception $e ) {
			$tr->rollBack ();
			return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', $e->getMessage()); 
		}
	}
	
	
	/**
	 * @desc 删除入库单
	 * @author liaojianwen
	 * @date 2016-11-28
	 */
	public function delInstore($ids)
	{
		if(empty($ids)){
			return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'param is empty' );
		}
		$_ids = explode ( ',', $ids );
		
		$tT = Yii::$app->db->beginTransaction ();
		try {
			foreach ( $_ids as $id ) {
				$res_instore = InstoreDAO::getInstance ()->updateByPk ( $id, ['delete_flag' => EnumOther::DELETED] );
				if(!$res_instore){
					$tT->rollBack();
					return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'del_instore fail');
				}
				//instore_detail
				$instore_det = InstoreDetailDAO::getInstance()->iupdate(['delete_flag'=>EnumOther::DELETED], "instore_id=:id", [':id'=>$id]);
				if(!$instore_det){
					$tT->rollBack();
					return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','del_instore_det fail');
				}
				//更新product_quantity
				$fields = [
					't.goods_id',
					't.quantity',
					't.transaction_id',
					'd.unit',
					'i.warehouse_id',
					'i.instore_no',
					'i.instore_type',
					'd.unit',
					'd.instore_det_id'
				];
				$conditions = "t.delete_flag = :flag";
				$params = [
					':flag'=>EnumOther::NO_DELETE,
				];
				$joinArray = [
					[
						'instore i',
						'i.instore_no = t.origin_id and i.instore_id = '.$id,
						'right'=>'',
					],
					[
						'instore_detail d',
						'd.instore_det_id = t.origin_line_id',
						'left'=>''
					]
				];
				$trans_select = TransactionDAO::getInstance()->iselect($fields, $conditions, $params,'all',"t.create_time ASC",$joinArray,'t');
				if (! empty ( $trans_select )) {
					// 已确认的入库单才有transtions,减库存
					foreach ( $trans_select as $trans ) {
						//记录更新product 前的quantity
						$PRODUCT = ProductDAO::getInstance()->iselect("quantity", "product_id = :pid", [':pid'=>$trans['goods_id']],'one');
						//product 更新数量
						$pro_minus = ProductDAO::getInstance ()->updateAllCounters ( [ 
							'quantity' => - $trans ['quantity'], 
						 ], "product_id =:id", [ 
								':id' => $trans ['goods_id'] 
							] );
					
						if (! $pro_minus) {
							$tr->rollBack ();
							return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'update product quantity failure' );
						}
						
						//product_update_log 商品更新记录
						$_order_type = Utility::getArrayValue(EnumOriginType::$origin_type, $trans['instore_type']);
						
						$log_columns = [
								'product_id' => $trans ['goods_id'],
								'update_num' => $trans ['quantity'],
								'num_unit' => $trans['unit'],
								'origin_id' => $id,
								'origin_no' => $trans['instore_no'],
								'origin_line_id'=> $trans['instore_det_id'],
								'origin_type'=> $trans['instore_type'],
								'update_time'=> strtotime(date('Y-m-d')),
								'flag'=> EnumOther::OUT_FLAG,
								'initial_num'=> $PRODUCT['quantity'],//上期数量
								'remark'=> $_order_type . EnumOther::MINUS.',入库单删除',
								'warehouse_id' => $trans['warehouse_id'],
								'create_man' => Yii::$app->user->id,
						];
						$res_log = ProductUpdateLogDAO::getInstance()->iinsert($log_columns, true);
						if(! $res_log){
							$tr->rollBack();
							return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'product update log failure');
						}
						
						//删除transaction 数据
						$columns = [
							'delete_flag'=>EnumOther::DELETED,
						];
						$conditions = "transaction_id = :tid";
						$params = [
							':tid'=>$trans['transaction_id'],
						];
						$trans_update = TransactionDAO::getInstance()->iupdate($columns, $conditions, $params);
						
						if(empty($trans_update)){
							$tT->rollBack();
							return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','tansaction del fail');
						}
							// 更新stock_file 分仓表信息
						$stock_minus = StockPileDAO::getInstance ()->updateAllCounters ( [ 
								'quantity' => - $trans ['quantity'] 
						], "warehouse_id =:wid and product_id=:pid and delete_flag =:flag", [ 
								':wid' => $trans ['warehouse_id'],
								':pid' => $trans ['goods_id'],
								':flag' => EnumOther::NO_DELETE 
						] );
						if(! $stock_minus){
							$tr->rollBack ();
							return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'update stock pile quantity failure'); 
						}
					}
				}

			}
			$tT->commit();
			return $this->handleApiFormat(EnumOther::ACK_SUCCESS,'');
		} catch ( \Exception $e ) {
			$tT->rollBack ();
			return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', $e->getMessage());
		}
	}
	
	/**
	 * 获取入库明细
	 * @author liaojianwen
	 * @date 2016-12-29
	 */
	public function getInstoreDet($id)
	{
		if (! $id) {
			return $this->handleApiFormat ( EnumOther::ACK_FAILURE, '', 'param is empty' );
		}
		$fields = [
				'instore_det_id',
				'd.instore_id',
				'd.goods_id',
				'p.product_name',
				'p.product_sn',
				'd.quantity',
				'd.unit',
				'u.unit_name',
				'd.price',
				'd.amount',
				'd.remark',
		];
	
		$joinArr = [
				[
						"product p",
						"p.product_id = d.goods_id"
				],
				[
						"unit u",
						"u.unit_id = d.unit"
				]
		];
		$conditions = "d.instore_id = :id and d.delete_flag = :dflag";
		$params = [
				':id' => $id,
				':dflag' => EnumOther::NO_DELETE,
		];
		$result = InstoreDetailDAO::getInstance()->iselect($fields, $conditions, $params, 'all',"instore_det_id ASC", $joinArr,'d');
		if(empty($result)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE,'','no data found');
		}
		return $this->handleApiFormat(EnumOther::ACK_SUCCESS, $result);
	}
	
	
	/**
	 * @desc 获取其他入库汇总数据
	 * @author liaojianwen
	 * @date 2018-01-30
	 */
	public function getInstoreSummary($pageInfo, $cond)
	{
		if(empty($pageInfo)){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'pageInfo is empty');
		}
		if(!isset($cond['starTime']) || empty($cond['starTime'])){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'search params time is empty');
		}
		$cond['starTime'] = strtotime($cond['starTime']);
		$cond['endTime'] = strtotime($cond['endTime']);
		$result =InstoreDetailDAO::getInstance()->getInstoreSummary($cond, $pageInfo);
		if(!$result){
			return $this->handleApiFormat(EnumOther::ACK_FAILURE, '', 'no data found');
		}
		return $this->handleApiFormat(EnumOther::ACK_SUCCESS, $result);
	}
}